/*
  * Mirante Tecnologia
  * Copyright 2010, Mirante Informatica LTDA, 
  * and individual contributors as indicated by the @authors tag
  *
  * This is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as
  * published by the Free Software Foundation; either version 2.1 of
  * the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this software; if not, write to the Free
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  */
package com.miranteinfo.seam.framework.service;

import java.util.ArrayList;
import java.util.List;

import org.jboss.seam.annotations.Create;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Transactional;
import org.jboss.seam.core.Events;
import org.jboss.seam.log.Log;

import com.miranteinfo.seam.framework.service.annotation.TransactionSupport;

/**
 * Classe suporte a todos os services. Possui metodos que sao utilizados para o controle 
 * transacional implementado pelo {@link TransactionSupportInterceptor}
 * 
 * @author lucas lins
 *
 */
@Transactional
@TransactionSupport
public abstract class ServiceSupport extends GenericService{
	
	private static final long serialVersionUID = 1L;

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// ATTRIBUTES
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	@Logger
	public Log log;
	
	private List<Event> events;
	
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// PUBLIC METHODS
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	@Create
	public void create(){
		events = null;
	}
	
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// DEFAULT METHODS
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	/**
	 * Faz o flush da sessao do hibernate
	 */
	void flush(){
		getSession().flush();
	}
	
	/**
	 * Lanca todos os eventos armazenados na pilha de eventos
	 */
	void raiseEvents(){
		if(events != null && !events.isEmpty()){
			for(Event event : events){
				try{
					if(event.isAsynchronous()){
						Events.instance().raiseAsynchronousEvent(event.getEventName(), event.getParams());
					}else{
						Events.instance().raiseEvent(event.getEventName(), event.getParams());
					}
				}catch (Exception e) {
					log.warn("Event: " + event.getEventName() + " failed!", e);
				}
			}
		}
	}
	
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// PROTECTED METHODS
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	/**
	 * Lanca o evento ao final da transacao caso esta seja bem sussucedida.
	 */
	protected void raiseEvent(String event, Object ... params){
		raiseEvent(event, false, params);
	}
	
	/**
	 * Lanca o evento ao final da transacao caso esta seja bem sussucedida.
	 */
	protected void raiseAsynchronousEvent(String event, Object ... params){
		raiseEvent(event, true, params);
	}
	
	/**
	 * Lanca o evento ao final da transacao caso esta seja bem sussucedida.
	 */
	protected void raiseEvent(String event, boolean asynchronous, Object ... params){
		if(event == null){
			throw new RuntimeException("Event must be not null.");
		}
		
		if(events == null){
			events = new ArrayList<Event>();
		}
		
		events.add(new Event(event, params, asynchronous));
	}
	
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// INNER CLASS
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	class Event{
		
		private String eventName;
		private Object[] params;
		private boolean asynchronous;
		
		public Event(String eventName, Object[] params, boolean asynchronous) {
			super();
			this.eventName = eventName;
			this.params = params;
			this.asynchronous = asynchronous;
		}

		public String getEventName() {
			return eventName;
		}
		public Object[] getParams() {
			return params;
		}
		public boolean isAsynchronous() {
			return asynchronous;
		}
	}
	
}